import { toJS } from 'mobx';
import { Dropdown, Spin } from 'antd';
import { WeaInput, WeaLocaleProvider } from 'ecCom';
import defaultData from './data';
import View from '../base/View';
import { Map } from 'react-amap';
import { When } from 'react-if';
import classNames from 'classnames';
import ThirdParty from '../../view/third-party';
import './index.less';

const getLabel = WeaLocaleProvider.getLabel;
const formatMultiLang = WeaLocaleProvider.formatMultiLang;

const thirdParty = new ThirdParty();

export default class LBSView extends View {
  constructor(props) {
    super(props);

    this.state = {
      formattedAddress: '',
      lat: '',
      lng: '',
      locationOpts: [],
      filterVal: '',
      centerLocalName: '',
      showMapPage: false,
      value: props.value,
    };

    this.data = props.data;
    this.addressListRef = null;
    this.map = null;
    this.marker = null;
    this.placeSearch = null;
    this.geocoder = null;
    this.location = null;
    this.mapCenter = { longitude: 120, latitude: 30 };
    this.mapEvents = {
      created: (mapInstance) => {
        this.map = mapInstance;

        AMap.plugin(['AMap.PlaceSearch', 'AMap.Geocoder', 'AMap.Geolocation'], () => {
          this.placeSearch = new AMap.PlaceSearch({
            pageSize: props.data.num,
          });
          this.geocoder = new AMap.Geocoder();
          this.marker = new AMap.Marker();
          this.location = new AMap.Geolocation({
            enableHighAccuracy: true, // 是否使用高精度定位，默认:true
            timeout: 10000, // 超过10秒后停止定位，默认：无穷大
            buttonPosition: 'RB', // 定位按钮的停靠位置
            buttonOffset: new AMap.Pixel(10, 20), // 定位按钮与设置的停靠位置的偏移量，默认：Pixel(10, 20)
            zoomToAccuracy: true, // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见，默认：false
          });

            this.location.getCurrentPosition();
            AMap.event.addListener(this.location, 'complete', this.onComplete); // 返回定位信息
            AMap.event.addListener(this.location, 'error', this.onError);
         });
      },
      click: (location) => {
        this.onMapClick(location, this.data.type);
      },
    };
  }

  // 高德地图成功获取定位
  onComplete = (data) => { 
    const { value } = this.state;
    const { formattedAddress, position } = data;
    const { lat, lng } = position;
    const val = {
      address: formattedAddress,
      location: position,
      name: this.data.name,
    };

    // 数据详细中修改数据时，先定位到保存的位置
    if (toJS(value)) {
      const { lat, lng } = value;

      this.setState({
        lat,
        lng,
      });

      return this.getLocation([lng, lat], '3');
    }

    if (formattedAddress) {
      this.setState({
        formattedAddress,
        lat,
        lng,
      }, () => {
        this.getLocation(formattedAddress);
        this.onSelectChange(val, true);
      });
    }
  }

  // 高德地图获取定位失败
  onError = () => { 
    // 第三方获取定位接口
    thirdParty.excu('getCurrentLocation').then((res) => {
      const { longitude, latitude } = res;
      // 微信未配置服务时，获取不到定位位置
      const lat = latitude || 34.50000;
      const lng = longitude || 121.43333;
      const lnglat = [ lng, lat ];

      const val = {
        address: '',
        location: { lat, lng },
        name: this.data.name,
      };

      this.setState({ lat, lng });
      this.getLocation([longitude, latitude]);
      this.onSelectChange(val, true);
      this.getAddress(lnglat).then((r) => {
        let data = {
          address: r ? `${r} - ${this.data.name}` : '',
          lat,
          lng,
        };
  
        this.handleValueChange(toJS(data));
      });
    });
  }

  onMapClick = (location, type) => {
    const { value } = this.state;
    const { lng, lat } = location.lnglat;
    let newType = type;
    // 数据详情中可修改地址
    if (toJS(value)) {
      newType = '3';
    }

    this.setState({ lng, lat }, () => {
      this.getLocation([lng, lat], newType);
    });
  }

  getAddress = (lnglat) => {
    const { formattedAddress } = this.state;

    return new Promise((res) => {
      this.geocoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.regeocode) {
          const address = result.regeocode.formattedAddress;

          res(address);
        } else {
          res(formattedAddress);
        }
      });
    });
  }

  // 定位到设置的位置
  getLocation = (address, type = '0') => { 
    if (!this.placeSearch) return;

    // 定位类型为1、2 时， 地图上的位置不能改变
    const result = ['1', '2'].some(d => type === d);
    if (result) return;

    this.setState({
      isFail: false,
    });

    if (_.isArray(address)) {
      this.map.remove(this.marker);
      this.map.add(this.marker);
      this.marker.setPosition(address);
      this.map.setFitView(this.marker);
    } else {
      this.placeSearch.search(address, (status, result) => {
        if (status === 'complete' && result.info === 'OK') {
          this.map.remove(this.marker);
          this.map.add(this.marker);
          this.marker.setPosition(result.poiList.pois[0].location);
          this.map.setFitView(this.marker);
        } else {
          this.setState({
            isFail: true,
          });
        }
      });
    }

    const { lat, lng } = this.state;
    // 中心点坐标
    const cpoint = [lng, lat]; 

    this.getSearchNearBy(cpoint);
  }

  // 获取目标附近热点信息
  getSearchNearBy = (cpoint) => { 
    const { radius } = this.props.data;

    this.placeSearch.searchNearBy('', cpoint, radius, (status, result) => {
      if (status === 'complete' && result.info === 'OK') {
        const { pois } = result.poiList;

        this.setState({ locationOpts: pois });
      }
    });
  }

  // 改变中心目标
  onCenterPointChange = (cpoint, name, isInit) => { 
    const { lat, lng } = cpoint;

    this.setState({ lat, lng, centerLocalName: name }, () => {
      this.getLocation([lng, lat]);
      if (!isInit) {
        this.toggleContent(false);
      }
    });
  }

  // 模糊查询地址
  filterLocation = (value) => { 
    this.setState({ filterVal: value });
  }

  toggleContent = (showMapPage) => {
    this.setState({ showMapPage });
  }

  onSelectChange = (val, isInit) => {
    const { location, name } = val;
    const { lat, lng } = location;

    this.getAddress(location).then((r) => {
      let data = {
        address: r ? `${r} - ${name}` : '',
        lat,
        lng,
      };

      this.handleValueChange(toJS(data));
    });

    this.onCenterPointChange(location, name, isInit);
  }

  // 指定滚动条到顶部
  toTop = () => { 
    const element = this.addressListRef;

    if (element) {
      setTimeout(() => {
        element.scrollTop = 0;
      }, 0);
    }
  }

  searchFilter = (val) => {
    const { filterVal } = this.state;

    const result = val.filter(item => !!~item.name.indexOf(filterVal) || !!~item.address.indexOf(filterVal));

    return result;
  }

  getMenu = (type) => {
    const { locationOpts, lat, lng } = this.state;
    const { num, radius } = this.props.data;
    const menuSetInfo = num && radius;

    let hotPoint = locationOpts;

    if (hotPoint[0] && !hotPoint[0].hasOwnProperty('hide')) {
      hotPoint.unshift({
        name: getLabel('519474', '不显示位置'),
        location: { lat, lng },
        address: '',
        hide: true,
      });
    }

    if (type === '1' || !menuSetInfo) {
      hotPoint = locationOpts.slice(0, 2);
    }

    const searchResult = this.searchFilter(hotPoint);

    return (
      <ul className="location-menu">
        { hotPoint.length ? <li>
          <WeaInput ecId={`${this && this.props && this.props.ecId || ''}_WeaInput@qnnvyl`} placeHolder={getLabel('519475', '搜索地址')} onChange={this.filterLocation} />
        </li> : null
        }
          <div className="location-list" ref={e => this.addressListRef = e}>
            {
              !_.isEmpty(searchResult) ?
              searchResult.map((d, i) => (
                <li
                  key={d.id}
                  className={classNames('location-menu-item', { 'list-highlight': i === 1 })}
                  onClick={() => this.onSelectChange(d)}
                >
                  <span className="text-elli position" title={d.name}>
                    { i === 1 ? `[${getLabel('34177', '当前位置')}]-${d.name}` : d.name }
                  </span>
                  <span className="text-elli address" title={d.address}>
                    { d.address }
                  </span>
                </li>
              ))
               : 
              <div className="not-found">搜索地址不在范围内!</div>
            }
          </div>
      </ul>
    );
  }

  getMenuForMobile = (type) => {
    const { locationOpts } = this.state;
    const { num, radius } = this.props.data;
    const menuSetInfo = num && radius;

    let hotPoint = locationOpts;

    // 处理定位类型为1时, 首次加载热点问题
    if (type === '1' || !menuSetInfo) {
      hotPoint = hotPoint.slice(0, 1);
    }

    if (hotPoint.length > 0) {
      return (
        hotPoint.map((d, i) => (
          <div
            className={classNames('lbs-list', { 'list-highlight': i === 0 })}
            onClick={() => this.onSelectChange(d)}
          >
            <div className="lbs-list-position" >
              { i === 0 ? `[${getLabel('34177', '当前位置')}]-${d.name}` : d.name }
            </div>
            <div className="lbs-list-address" >
              {d.address}
            </div>
          </div>
        ))
      );
    }
      return (
        <div className="lbs-list-loading">
          <Spin ecId={`${this && this.props && this.props.ecId || ''}_Spin@0ioryc`} />
          <div className="lbs-list-loading-tips">{getLabel('519476', '附近热点地址加载中...')}</div>
        </div>
      );
  }

  renderForMobile(data) {
    const { showMapPage, centerLocalName } = this.state;
    const { name, type } = data;
    const currentName = centerLocalName || name;

    return (
      <div className="wea-edc-lbs-wrapper">
        <div className="lbs-mobile">
          <div
            className="lbs-position"
            onClick={() => this.toggleContent(true)}
          >
              <i className="icon-edc-f-lbs" />
              {formatMultiLang(currentName)}
            </div>
        </div>
        <div className={showMapPage ? 'lbs-map-wrapper show' : 'lbs-map-wrapper'}>
          <div className="lbs-mobile-map">
            <Map ecId={`${this && this.props && this.props.ecId || ''}_Map@1iv61p`}
              zoom={5}
              jogEnable={false}
              animateEnable={false}
              center={this.mapCenter}
              events={this.mapEvents}
            />
          </div>
          <div className="lbs-mobile-container">
            <When ecId={`${this && this.props && this.props.ecId || ''}_When@aat4ro`} condition={showMapPage}>
              <div className="lbs-mobile-list">
                { this.getMenuForMobile(type) }
              </div>
            </When>
            <div className="lbs-mobile-btns">
              <div className="lbs-btns-hide"
                onClick={() => {
                this.setState({ centerLocalName: getLabel('519474', '不显示位置') });
                this.toggleContent(false);
              }}
              >{getLabel('519474', '不显示位置')}</div>
              <div className="lbs-btns-cancel"
                onClick={() => {
                this.toggleContent(false);
              }}
              >{getLabel('31129', '取消')}</div>
            </div>
          </div>
        </div>
      </div>
    );
  }

  renderForPC(data) {
    const { name, type } = data;
    const { centerLocalName } = this.state;
    const currentName = centerLocalName || name;

    return (
      <div className="wea-edc-lbs">
        <div className="map">
          <Dropdown ecId={`${this && this.props && this.props.ecId || ''}_Dropdown@ntjz8o`}
            overlay={this.getMenu(type)}
            trigger="click"
            onClick={() => this.toTop()}
          >
            <div className="location-drop" >
              <i className="icon-edc-f-lbs" />
              <input
                disabled
                className="location-drop-input"
                title={formatMultiLang(currentName)}
                value={formatMultiLang(currentName)}
              />
            </div>
          </Dropdown>
          <Map ecId={`${this && this.props && this.props.ecId || ''}_Map@rchvjh`}
            zoom={5}
            jogEnable={false}
            animateEnable={false}
            center={this.mapCenter}
            events={this.mapEvents}
          />
        </div>
      </div>
    );
  }

  renderForReadonly(data, value) {
    const { address } = value;

    return (
      <div>
        { address || '' }
      </div>
    );
  }
}

LBSView.defaultProps = {
  data: defaultData,
  value: '',
};
